package com.ccovo.config.satoken;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.strategy.SaAnnotationStrategy;
import cn.dev33.satoken.util.SaResult;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.PostConstruct;

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
    // 注册 Sa-Token 拦截器，打开注解式鉴权功能
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册 Sa-Token 拦截器，打开注解式鉴权功能
        registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
    }

    // 拦截除了 /user/doLogin 的所有请求,并且需要用户已登录才可放行
//    @Override
//    public void addInterceptors(InterceptorRegistry registry) {
//        // 注册 Sa-Token 拦截器，校验规则为 StpUtil.checkLogin() 登录校验。
//        registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
//                .addPathPatterns("/**")
//                // 放行接口文档相关路径
//                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**",
//                        "/api", "/api-docs", "/api-docs/**", "/doc.html*", "/doc.html#/**")
//                .excludePathPatterns("/login");
//    }

    /**
     * .isAnnotation(false) 用于关闭注解鉴权功能，这样只会走路由拦截校验
     */
//    @Override
//    public void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(
//                new SaInterceptor(handle -> {
//                    SaRouter.match("/**").check(r -> StpUtil.checkLogin());
//                }).isAnnotation(false)  // 指定关闭掉注解鉴权能力，这样框架就只会做路由拦截校验了
//        ).addPathPatterns("/**");
//    }

    /**
     * 自定义认证规则, 可以对所有路由生效, 也可以对模块进行划分鉴权
     * match: 匹配拦截的路径, notMatch: 排除掉的路径, check: 校验所执行的动作
     */
//    @Override
//    public void addInterceptors(InterceptorRegistry registry) {
//        // 注册 Sa-Token 拦截器，定义详细认证规则
//        registry.addInterceptor(new SaInterceptor(handler -> {
//            // 指定一条 match 规则
//            SaRouter
//                    .match("/**")    // 拦截的 path 列表，可以写多个 */
//                    .notMatch("/user/doLogin")        // 排除掉的 path 列表，可以写多个
//                    .check(r -> StpUtil.checkLogin());        // 要执行的校验动作，可以写完整的 lambda 表达式
//
//            // 根据路由划分模块，不同模块不同鉴权
//            SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
//            SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
//            SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
//            SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
//            SaRouter.match("/notice/**", r -> StpUtil.checkPermission("notice"));
//            SaRouter.match("/comment/**", r -> StpUtil.checkPermission("comment"));
//
//            // 甚至你可以随意的写一个打印语句
//            SaRouter.match("/**", r -> System.out.println("----啦啦啦----"));
//            // 连缀写法
//            SaRouter.match("/**").check(r -> System.out.println("----啦啦啦----"));
//
//        })).addPathPatterns("/**");
//
//        /**
//         * 使用 SaRouter.stop() 可以提前退出匹配链
//         * 代码运行到第二条匹配链时,会在stop()函数处提前退出整个匹配函数,忽略剩余的所有match匹配
//         *
//         * SaRouter.stop() 会停止匹配，进入Controller。
//         * SaRouter.back() 会停止匹配，直接返回结果到前端。
//         */
//        registry.addInterceptor(new SaInterceptor(handler -> {
//            SaRouter.match("/**").check(r -> System.out.println("进入1"));
//            SaRouter.match("/**").check(r -> System.out.println("进入2")).stop();
//            SaRouter.match("/**").check(r -> System.out.println("进入3"));
//            SaRouter.match("/**").check(r -> System.out.println("进入4"));
//            // SaRouter.back() 停止匹配，结束执行，直接向前端返回结果
//            SaRouter.match("/user/back").back("要返回到前端的内容");
//            SaRouter.match("/**").check(r -> System.out.println("进入5"));
//
//            /**
//             * 进入 free 独立作用域
//             * 打开一个独立的作用域，使内部的 stop() 不再一次性跳出整个 Auth 函数，而是仅仅跳出当前 free 作用域
//             */
//            SaRouter.match("/**").free(r -> {
//                // SaRouter.match("/a/**").check();
//                // SaRouter.match("/b/**").check().stop();
//                // SaRouter.match("/c/**").check();
//            });
//            // 执行 stop() 函数跳出 free 后继续执行下面的 match 匹配
//            SaRouter.match("/**").check(r -> System.out.println("跳出free作用域后执行..."));
//
//        })).addPathPatterns("/**");
//    }

    /**
     * 注册 [Sa-Token 全局过滤器]
     */
//    @Bean
//    public SaServletFilter getSaServletFilter() {
//        return new SaServletFilter()
//
//                // 指定 [拦截路由] 与 [放行路由]
//                .addInclude("/**")// .addExclude("/favicon.ico")
//
//                // 认证函数: 每次请求执行
//                .setAuth(obj -> {
//                    // System.out.println("---------- sa全局认证 " + SaHolder.getRequest().getRequestPath());
//                    // SaManager.getLog().debug("----- 请求path={}  提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue());
//
//                    // 权限校验 -- 不同模块认证不同权限
//                    //		这里你可以写和拦截器鉴权同样的代码，不同点在于：
//                    // 		校验失败后不会进入全局异常组件，而是进入下面的 .setError 函数
//                    SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
//                    SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
//                    SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
//                    SaRouter.match("/notice/**", r -> StpUtil.checkPermission("notice"));
//                    SaRouter.match("/comment/**", r -> StpUtil.checkPermission("comment"));
//                })
//
//                // 异常处理函数：每次认证函数发生异常时执行此函数
//                .setError(e -> {
//                    System.out.println("---------- sa全局异常 ");
//                    return SaResult.error(e.getMessage());
//                })
//
//                // 前置函数：在每次认证函数之前执行（BeforeAuth 不受 includeList 与 excludeList 的限制，所有请求都会进入）
//                .setBeforeAuth(r -> {
//                    // ---------- 设置一些安全响应头 ----------
//                    SaHolder.getResponse()
//                            // 服务器名称
//                            .setServer("sa-server")
//                            // 是否可以在iframe显示视图： DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
//                            .setHeader("X-Frame-Options", "SAMEORIGIN")
//                            // 是否启用浏览器默认XSS防护： 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时，停止渲染页面
//                            .setHeader("X-XSS-Protection", "1; mode=block")
//                            // 禁用浏览器内容嗅探
//                            .setHeader("X-Content-Type-Options", "nosniff")
//                    ;
//                })
//                ;
//    }
//
    /**
     * 重写 Sa-Token 框架内部算法策略
     */
    @PostConstruct
    public void rewriteSaStrategy() {
        // 重写Sa-Token的注解处理器，增加注解合并功能
        SaAnnotationStrategy.instance.getAnnotation = (element, annotationClass) -> {
            return AnnotatedElementUtils.getMergedAnnotation(element, annotationClass);
        };
    }


}

